昨天說完了基礎的單元測試,今天讓我們好好的了解如何透過更好的方式來進行單元測試。
從昨天的範例中可以看出,如果我們要比對結果是否正確必須要自己寫 if/else
來判斷,這樣程式並不簡潔,當然我們可以自行封裝方法,但已經有大神幫我們寫好的專屬的測試庫 - testify
透過 go get
的方式進行安裝
go get -u github.com/stretchr/testify
我們這邊來改寫昨天的單元測試方法
func TestAdd(t *testing.T) {
for i, in := range input {
result := Add(in[0], in[1])
t.Log("in =", in, "output should be", output[i], " actual output equal", result)
if output[i] == result {
t.Log("Pass")
} else {
t.Error("Case", i, "is failed")
}
}
}
首先我們匯入 testify
中的 require
模組
import "github.com/stretchr/testify/require"
接著我們將原先的 if
取代成 require.Equal
方法,testify 幫我們封裝了許多好用的方法,包括了 Equal
、Contains
、Empty
等等,讓我們可以不用再寫 if
來判斷
func TestAdd(t *testing.T) {
for i, in := range input {
result := Add(in[0], in[1])
t.Log("in =", in, "output should be", output[i], " actual output equal", result)
require.Equal(t, output[i], result)
}
}
suite
是由 testify
所提供的 package,他可以幫我們針對每個測試案例做 前置作業
與 後置操作
,讓我們可以更完整的掌握要測試案例的生命週期。
首先我們定義一個 struct 名為 Suite
,在這個結構裡面繼承了 suite
的 Suite
。
type Suite struct {
suite.Suite
finalTest int
finalResult int
testInput [][]int
testOutput []int
}
suite
有提供 SetupSuite
方法讓我們實作,因此可以在此方法內進行參數的初始化,在這邊我們先將測試的參數進行初始化。
func (s *Suite) SetupSuite() {
s.testInput = [][]int{
{1, 2},
{2, 3},
{3, 4},
}
s.testOutput = []int{3, 5, 7}
s.finalTest = 0
for _, n := range s.testOutput {
s.finalResult += n
}
}
要使用 suite
來做單元測試,我們可以在剛才建立的 Suite
struct 中實現方法,如果要測試 Add
方法的話,就實作 TestAdd
。
func (s *Suite) TestAdd() {
for i, in := range s.testInput {
result := Add(in[0], in[1])
s.finalTest += result
require.Equal(s.T(), s.testOutput[i], result, "should be equal")
}
}
在測試案例測完的時候,可以實作 AfterTest
方法來檢查此測試用例是否有誤。
func (s *Suite) AfterTest(_, _ string) {
require.Equal(s.T(), s.finalResult, s.finalTest, "should be equal")
}
透過實作 TestStart
方法來設定起始點,裡面就使用 suite.Run
的方式將 Suite
struct 進行初始化。
func TestStart(t *testing.T) {
suite.Run(t, new(Suite))
}
將上述的程式集合起來程式碼如下
package cal
import (
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
"testing"
)
type Suite struct {
suite.Suite
finalTest int
finalResult int
testInput [][]int
testOutput []int
}
func (s *Suite) SetupSuite() {
s.testInput = [][]int{
{1, 2},
{2, 3},
{3, 4},
}
s.testOutput = []int{3, 5, 7}
s.finalTest = 0
for _, n := range s.testOutput {
s.finalResult += n
}
}
//AfterTest 用於測試完畢之後的檢查
func (s *Suite) AfterTest(_, _ string) {
require.Equal(s.T(), s.finalResult, s.finalTest, "should be equal")
}
//TestStart 為測試程式進入點
func TestStart(t *testing.T) {
suite.Run(t, new(Suite))
}
func (s *Suite) TestAdd() {
for i, in := range s.testInput {
result := Add(in[0], in[1])
s.finalTest += result
require.Equal(s.T(), s.testOutput[i], result, "should be equal")
}
}
依照正確執行,執行結果如下
=== RUN TestStart
=== RUN TestStart/TestAdd
--- PASS: TestStart (0.00s)
--- PASS: TestStart/TestAdd (0.00s)
PASS
我們可以透過修改 SetupSuite
將測試結果改成錯誤的
func (s *Suite) SetupSuite() {
s.testInput = [][]int{
{1, 2},
{2, 3},
{3, 4},
}
s.testOutput = []int{3, 5, 8}
s.finalTest = 0
for _, n := range s.testOutput {
s.finalResult += n
}
}
接著重新運行一次測試程式,顯示結果如下
=== RUN TestStart
=== RUN TestStart/TestAdd
TestStart/TestAdd: cal_test.go:44:
Error Trace: cal_test.go:44
Error: Not equal:
expected: 8
actual : 7
Test: TestStart/TestAdd
Messages: should be equal
TestStart/TestAdd: cal_test.go:33:
Error Trace: cal_test.go:33
suite.go:137
panic.go:617
testing.go:657
cal_test.go:44
Error: Not equal:
expected: 16
actual : 15
Test: TestStart/TestAdd
Messages: should be equal
--- FAIL: TestStart (0.00s)
--- FAIL: TestStart/TestAdd (0.00s)
Expected :16
Actual :15
<Click to see difference>
FAIL
從上述結果可以看到,他會顯示預期結果與實際運行結果不符,顯示相關的訊息,這樣的方式可以讓我們更好查出錯誤在哪。
今天透過簡單介紹 testify
這個單元測試的 package,讓我們在撰寫單元測試可以更快速且精準。